/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.songlin.houxin.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.songlin.houxin.admin.api.dto.*;
import com.songlin.houxin.admin.api.entity.Channel;
import com.songlin.houxin.admin.api.entity.ChannelStatistic;
import com.songlin.houxin.admin.api.vo.BasePageVO;
import com.songlin.houxin.admin.api.vo.ChannelStatisticVO;
import com.songlin.houxin.admin.api.vo.ChannelVO;
import com.songlin.houxin.admin.mapper.ChannelMapper;
import com.songlin.houxin.admin.service.ChannelService;
import com.songlin.houxin.admin.service.ChannelStatisticService;
import com.songlin.houxin.common.core.exception.BusinessAssert;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 渠道表
 *
 * @author pig code generator
 * @date 2022-03-05 23:31:25
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class ChannelServiceImpl extends ServiceImpl<ChannelMapper, Channel> implements ChannelService {
    private final ChannelStatisticService channelStatisticService;
    private static final String LEVEL = "3";
    private final RedisTemplate<String, Object> redisTemplate;


    @Override
    public List<ChannelStatisticVO> exportChannelStatisticInfo(ChannelStatistiDTO dto) {
        dto.setPageIndex(1L).setPageSize(Long.MAX_VALUE);
        BasePageVO<ChannelStatisticVO> basePageVO = queryChannelStatisticInfo(dto);
        return basePageVO.getList();
    }

    @Override
    public void deleteBatchChannel(ChannelDeleteDTO dto) {
        this.removeBatchByIds(dto.getChannelIds());
    }

    @Override
    public BasePageVO<ChannelVO> queryChannelList(ChannelListDTO dto) {
        List<Channel> channelList = this.list(new LambdaQueryWrapper<Channel>().eq(Channel::getIsDelete, 0));
        Map<Integer, String> channelMap = channelList.stream().collect(Collectors.toMap(Channel::getId, Channel::getName));
        LambdaQueryWrapper<Channel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Channel::getIsDelete, 0);
        Optional.ofNullable(dto.getLevel()).ifPresent(level -> wrapper.eq(Channel::getLevel, level));
        Optional.ofNullable(dto.getName()).ifPresent(name -> wrapper.eq(Channel::getName, name));
        Optional.ofNullable(dto.getParentId()).ifPresent(pid -> wrapper.eq(Channel::getParentId, pid));
        Page<Channel> page = this.page(new Page<>(dto.getPageIndex(), dto.getPageSize()), wrapper);
        List<ChannelVO> channelVOS = JSONUtil.toList(JSONUtil.toJsonStr(page.getRecords()), ChannelVO.class);
        channelVOS.forEach(channelVO -> channelVO.setParentName(channelMap.getOrDefault(channelVO.getParentId(), "-")));
        return BasePageVO.instance(channelVOS, page.getTotal());
    }

    @Override
    public void updateChannel(ChannelUpdateDTO dto) {
        long count = this.count(Wrappers.<Channel>lambdaQuery()
                .eq(Channel::getName, dto.getName())
                .ne(Channel::getId, dto.getId()));
        BusinessAssert.isTrue(count < 1, "改名称已存在不能更新");
        Channel channel = new Channel();
        channel.setId(dto.getId());
        channel.setName(dto.getName());
        this.updateById(channel);
    }

    @Override
    public void saveChannel(ChannelSaveDTO dto) {
        Long count = this.count(Wrappers.<Channel>lambdaQuery().eq(Channel::getName, dto.getName()));
        BusinessAssert.isTrue(count == null || count == 0, "渠道名称不能重复");
        // Channel channel = ChannelConverter.INSTANCE.toChannel(dto);
        Channel channel = JSONUtil.toBean(JSONUtil.toJsonStr(dto), Channel.class);
        this.save(channel);
    }

    @Override
    public BasePageVO<ChannelStatisticVO> queryChannelStatisticInfo(ChannelStatistiDTO dto) {
        Object o = redisTemplate.boundValueOps("").get();
        BusinessAssert.isNull(o, "统计中");
        List<Channel> channelList = this.list(new LambdaQueryWrapper<Channel>().eq(Channel::getIsDelete, 0));
        Map<Integer, Channel> channelMap = channelList.stream().collect(Collectors.toMap(Channel::getId, Function.identity()));
        LambdaQueryWrapper<ChannelStatistic> wrapper = new LambdaQueryWrapper<>();
        Optional.ofNullable(dto.getChannelId()).ifPresent(id -> wrapper.eq(ChannelStatistic::getChannelId, id));
        Optional.ofNullable(dto.getChannelLevel()).ifPresent(level -> wrapper.eq(ChannelStatistic::getChannelLevel, level));
        String channelName = dto.getChannelName();
        if (StrUtil.isNotBlank(channelName)) {
            List<Integer> ids = new ArrayList<>();
            for (Channel value : channelMap.values()) {
                String name = value.getName();
                if (name.equalsIgnoreCase(channelName) || name.contains(dto.getChannelName())) {
                    ids.add(value.getId());
                }
            }
            ids.add(0);
            wrapper.in(ChannelStatistic::getChannelId, ids);
        }
        if (CollectionUtil.isNotEmpty(channelMap.keySet())) {
            wrapper.in(ChannelStatistic::getChannelId, channelMap.keySet().toArray());
        }
        Page<ChannelStatistic> page = channelStatisticService.page(new Page<>(dto.getPageIndex(), dto.getPageSize()), wrapper);
        //List<ChannelStatisticVO> vos = ChannelStatisticConverter.INSTANCE.toChannelStatisticVOList(page.getRecords());
        // List<ChannelStatisticVO> vos = JSONUtil.toList(JSONUtil.toJsonStr(page.getRecords()), ChannelStatisticVO.class);

        List<ChannelStatisticVO> vos = page.getRecords().stream().map(cs -> {
            ChannelStatisticVO vo = new ChannelStatisticVO();
            vo.setId(cs.getId());
            vo.setChannelId(cs.getChannelId());
            Channel channel = channelMap.get(vo.getChannelId());
            vo.setChannelName(channel.getName());
            vo.setChannelLevel(cs.getChannelLevel());
            vo.setCurrentDateActiveNo(cs.getCurrentDateActiveNo());
            vo.setCurrentMonthActiveNo(cs.getCurrentMonthActiveNo());
            vo.setTotalActiveNo(cs.getTotalActiveNo());
            DecimalFormat df = new DecimalFormat("0.00");
            String totalRebate = "0.00";
            String dayTotalRebate = "0.00";
            String monthTotalRebate = "0.00";

            if (Objects.nonNull(cs.getTotalRebate())) {
                totalRebate = df.format(new BigDecimal(cs.getTotalRebate()).divide(BigDecimal.valueOf(100), 2));
            }
            if (Objects.nonNull(cs.getCurrentDateRebate())) {
                dayTotalRebate = df.format(new BigDecimal(cs.getCurrentDateRebate()).divide(BigDecimal.valueOf(100), 2));
            }

            if (Objects.nonNull(cs.getCurrentMonthRebate())) {
                monthTotalRebate = df.format(new BigDecimal(cs.getCurrentMonthRebate()).divide(BigDecimal.valueOf(100), 2));
            }
            vo.setTotalRebate(totalRebate);
            vo.setDayTotalRebate(dayTotalRebate);
            vo.setMonthTotalRebate(monthTotalRebate);
            return vo;
        }).collect(Collectors.toList());
        vos.forEach(vo -> {

        });
        return BasePageVO.instance(vos, page.getTotal());
    }

    @Override
    public List<Tree<Long>> listSelectTree() {

        List<Channel> channels = this.list(Wrappers.<Channel>lambdaQuery().ne(Channel::getLevel, LEVEL).ne(Channel::getIsDelete, 1));

        List<TreeNode<Long>> collect = channels.stream().
                sorted(Comparator.comparing(Channel::getUpdateTime)).map(e -> {
            TreeNode<Long> treeNode = new TreeNode();
            treeNode.setId(e.getId().longValue());
            treeNode.setParentId(e.getParentId().longValue());
            treeNode.setName(e.getName());
            // 扩展属性
            Map<String, Object> extra = new HashMap<>(4);
            extra.put("level", e.getLevel());
            treeNode.setExtra(extra);
            return treeNode;
        }).collect(Collectors.toList());
        return TreeUtil.build(collect, 0L);
    }

}
